package io.github.junxworks.qt.modules.data.service.impl;

import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.google.common.collect.Lists;

import io.github.junxworks.ep.sys.constants.YesNo;
import io.github.junxworks.junx.core.util.DateUtils;
import io.github.junxworks.junx.core.util.NumberUtils;
import io.github.junxworks.junx.core.util.StringUtils;
import io.github.junxworks.junx.stat.Stat;
import io.github.junxworks.junx.stat.StatContext;
import io.github.junxworks.junx.stat.StatDefinition;
import io.github.junxworks.junx.stat.datawindow.DataBundle;
import io.github.junxworks.junx.stat.datawindow.DataWindowConstants;
import io.github.junxworks.junx.stat.datawindow.prioritywindow.Priorities;
import io.github.junxworks.junx.stat.function.FuncDef;
import io.github.junxworks.qt.commons.DateHandleService;
import io.github.junxworks.qt.modules.data.entity.DStockChangeStat;
import io.github.junxworks.qt.modules.data.mapper.StockStatMapper;
import io.github.junxworks.qt.modules.data.service.DataStoreService;
import io.github.junxworks.qt.modules.data.service.HistoryService;
import io.github.junxworks.qt.modules.data.service.StockStatService;
import io.github.junxworks.qt.modules.data.vo.DStockProfileVo;
import io.github.junxworks.qt.modules.tushare.TushareConstants;
import io.github.junxworks.qt.modules.tushare.entity.DStockTradeDaily;
import io.github.junxworks.qt.modules.tushare.service.BaseInfoService;
import io.github.junxworks.qt.modules.tushare.service.TradeInfoService;

@Service("StockStatService")
public class StockStatServiceImpl extends DateHandleService implements StockStatService {

	@Autowired
	private TradeInfoService tradeInfoService;

	@Autowired
	private BaseInfoService baseInfoService;

	@Autowired
	private StockStatMapper stockStatMapper;

	@Autowired
	private HistoryService historyService;

	@Autowired
	private DataStoreService dataStoreService;

	@Override
	public void statStockChangeByDate(String tradeDate) {
		handleDataByDate(tradeDate, d -> {
			stat(d);
		});
	}

	private void stat(String d) {
		if (tradeInfoService.isWeekend(d)) {
			return;
		}
		final String dd = tradeInfoService.queryTradeCalByOffset(d, -20);
		if (StringUtils.isNull(dd)) {
			return;
		}
		stockStatMapper.deleteStockChangeStatByDate(dd);//删除当日
		List<DStockProfileVo> profiles = baseInfoService.getAllProfiles();
		List<DStockChangeStat> stats = Lists.newArrayListWithCapacity(profiles.size());
		for (DStockProfileVo p : profiles) {
			try {
				List<DStockTradeDaily> trades = historyService.getTradeDataByCodeAndDateRange(p.getTsCode(), dd, d); //20天交易记录
				if (trades == null || trades.isEmpty()) {
					continue;//没有交易记录
				}
				DStockChangeStat stat = new DStockChangeStat();
				stat.setTsCode(p.getTsCode());
				stat.setTradeDate(dd);
				StatDefinition statModel = new StatDefinition();
				statModel.setDataWindowSize(20);
				statModel.setStatFunction(FuncDef.LINEAR_REGRESSION);
				statModel.setDataWindowType(DataWindowConstants.WIN_TYPE_PRIORITY);
				statModel.setDataWindowPriorityType(Priorities.FIFO.toString());
				Stat so = Stat.create(statModel);
				float min = 0;
				float max = 0;
				float start = trades.get(0).getClose();
				for (int i = 0, len = trades.size(); i < len || i < 20; i++) {
					DStockTradeDaily t = trades.get(i);
					float close = t.getClose();
					if (min == 0 || t.getClose() < min) {
						min = close;
					}
					if (t.getClose() > max) {
						max = close;
					}
					so.compose(new DataBundle(DateUtils.parseDate(t.getTradeDate(), "yyyyMMdd").getTime(), close));
					if (i == 1) {
						stat.setDc1(t.getChange());
						if (start < t.getClose()) {
							stat.setD1(YesNo.YES.getValue());
						} else {
							stat.setD1(YesNo.NO.getValue());
						}
					} else if (i == 5) {
						StatContext ctx = new StatContext();
						Object res = so.getValue(ctx);
						stat.setD5(Double.valueOf(String.valueOf(res)));
						stat.setDc5min(calChange(start, min));
						stat.setDc5max(calChange(start, max));
					} else if (i == 10) {
						StatContext ctx = new StatContext();
						Object res = so.getValue(ctx);
						stat.setD10(Double.valueOf(String.valueOf(res)));
						stat.setDc10min(calChange(start, min));
						stat.setDc10max(calChange(start, max));
					} else if (i == 19) {
						StatContext ctx = new StatContext();
						Object res = so.getValue(ctx);
						stat.setD20(Double.valueOf(String.valueOf(res)));
						stat.setDc20min(calChange(start, min));
						stat.setDc20max(calChange(start, max));
					}
				}
				stats.add(stat);
			} catch (Exception e) {
			}
		}
		dataStoreService.insertBatch(stats);
	}

	@Override
	public void statStockChangeByDateRange(String tradeDateRage) {
		handleDataDayByDay(tradeDateRage, 0, d -> {
			statStockChangeByDate(d);
		});
	}

	/*private boolean statStockChange(DStockChangeStat stat, DStockTradeDaily trade, int days) {
		Float price = trade.getClose();//统计日收盘价
		if (price == 0) {
			return false;
		}
		String tsCode = stat.getTsCode();
		String tradeDate = stat.getTradeDate();
		String targetSTradeDate = tradeInfoService.queryTradeCalByOffset(tradeDate, 1);
		StockStatDto s = null;
		if (days == 1) {
			s = stockStatMapper.queryStateChangeByDate(tsCode, targetSTradeDate);
		} else {
			String targetETradeDate = tradeInfoService.queryTradeCalByOffset(tradeDate, days);
			s = stockStatMapper.queryStateChangeByDateRange(tsCode, targetSTradeDate, targetETradeDate);
		}
		if (s == null) {
			return false;
		}
		byte change = change(price, s.getHigh());
		float max = calChange(price, s.getHigh());
		float min = calChange(price, s.getLow());
		if (days == 1) {
			stat.setD1(change);
			stat.setDc1(max);
		} else if (days == 5) {
			//			stat.setD5(change);
			stat.setDc5max(max);
			stat.setDc5min(min);
		} else if (days == 10) {
			//			stat.setD10(change);
			stat.setDc10max(max);
			stat.setDc10min(min);
		} else if (days == 20) {
			//			stat.setD20(change);
			stat.setDc20max(max);
			stat.setDc20min(min);
		}
		return true;
	}*/

	private byte change(Float start, Float end) {
		return (byte) (end > start ? 1 : end == start ? 0 : -1);
	}

	private float calChange(float start, float end) {
		return NumberUtils.devide((end - start) * 100, start, 2);
	}

	/**
	 * 按月来统计
	 *
	 * @param dateRange the date range
	 */
	public void statStockMvByDateRange(String dateRange) {
		handleDataMonthByMonth(dateRange, d -> {
			statStockMvByDate(d);
		});
	}

	/**
	 * 默认统计是上个月最后一个交易日的市值
	 *
	 * @param date the date
	 */
	public void statStockMvByDate(String date) {
		handleDataByDate(date, dd -> {
			Date d = DateUtils.addMonths(DateUtils.parse(dd, TushareConstants.TUSHARE_DATE_FORMAT), -1);
			String lastDay = StringUtils.replace(DateUtils.lastDayOfMonth(d), "-", "");
			String firstDay = StringUtils.replace(DateUtils.firstDayOfMonth(d), "-", "");
			stockStatMapper.deleteTotalMv(lastDay.substring(0, 6));
			dataStoreService.insertBatch(stockStatMapper.generateTotalMv(firstDay, lastDay), 500);
		});
	}

}
